package com.threeti.mecool.core.domain.model.plan.pojo;

import com.threeti.mecool.core.infrastructure.persistence.plan.JobRepository;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonManagedReference;
import org.springframework.beans.factory.annotation.Configurable;

import javax.annotation.Resource;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Configurable
@Entity
@Table(name = "DM_WF_JOB")
public class Job {
  public static final String CODE_JOB_STORE_OPENING = "WF_JOB_SO";
    private Long id;
    private Integer version;
    private String name;
    private String code;
    private List<Step> steps = new ArrayList<Step>();
    private Date updatedAt;
    private Integer removed;

    private JobRepository jobRepository;

    public Step createStep() {
        Step step = new Step();
        step.setJob(this);
        steps.add(step);
        return step;
    }

    public Step createStep(Task task, String name, boolean fixed) {
        Step step = createStep();
        step.setTask(task);
        step.setName(name);
        step.setFixed(fixed ? 1 : 0);
        step.createStepItems();
        return step;
    }

    public Step createStep(Task task, String name, boolean fixed, boolean optional) {
        Step step = createStep();
        step.setTask(task);
        step.setName(name);
        step.setFixed(fixed ? 1 : 0);
        step.setOptional(optional ? 1: 0);
        step.createStepItems();
        return step;
    }

    public Step createStep(Task task, String name) {
        return createStep(task, name, false);
    }

    //<editor-fold desc="static find">
    public static Job findById(Long id) {
        return jobRepository().findOne(id);
    }

    public static Job findByName(String name) {
        return jobRepository().findByName(name);
    }

    public static Job findByCode(String code) {
        return jobRepository().findByCode(code);
    }

    public static List<Job> findAll() {
        return jobRepository().findAll();
    }
    //</editor-fold>

    public void save() {
        for (int i = 0; i < steps.size(); i++) {
            Step step = steps.get(i);
            step.setStepsOrder(i);
        }
        updatedAt = new Date();
        jobRepository.save(this);
    }

    public void remove() {
        removed = 1;
        save();
    }

    @PrePersist
    @PreUpdate
    private void preSave() {
        validate();
    }

    private void validate() {
        validateSteps();
    }

    private void validateSteps() {
        for (Step step : getSteps()) {
            if (step.getCheckBox() == null || step.getCheckBox().equals(0)) {
                validateNoParallelSelectSingleStep(step);
            }
        }
    }

    private void validateNoParallelSelectSingleStep(Step step) {
        if (step.getTask().getAction() == TaskAction.SELECT_SINGLE) {
            for (StepItem stepItem : step.getStepItems()) {
                boolean hasSelectSingleStep = false;
                for (Step subStep : stepItem.getSteps()) {
                    if (subStep.getTask().getAction() == TaskAction.SELECT_SINGLE) {
                        if (hasSelectSingleStep) {
                            throw new RuntimeException("同一步骤或选项内不允许设置多个单选流程");
                        } else {
                            hasSelectSingleStep = true;
                        }
                    }
                }
            }
        }
        for (StepItem stepItem : step.getStepItems()) {
            for (Step subStep : stepItem.getSteps()) {
                validateNoParallelSelectSingleStep(subStep);
            }
        }
    }

    //<editor-fold desc="get/set">
    private static JobRepository jobRepository() {
        return new Job().jobRepository;
    }

    @Resource
    public void setJobRepository(JobRepository jobRepository) {
        this.jobRepository = jobRepository;
    }

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    @Version
    public Integer getVersion() {
        return version;
    }

    @Column(nullable=false, unique=true)
    public String getName() {
        return name;
    }

    @JsonManagedReference("job")
    @OneToMany(mappedBy = "job", cascade = CascadeType.ALL, orphanRemoval = true)
    @OrderBy("stepsOrder")
    public List<Step> getSteps() {
        return steps;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @JsonIgnore
    public Date getUpdatedAt() {
        return updatedAt;
    }

    @JsonIgnore
    public Integer getRemoved() {
        return removed;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Column(unique=true)
    public String getCode() {
      return code;
    }

    public void setCode(String code) {
      this.code = code;
    }

    public void setSteps(List<Step> steps) {
        this.steps = steps;
    }

    public void setUpdatedAt(Date updatedAt) {
        this.updatedAt = updatedAt;
    }

    public void setRemoved(Integer removed) {
        this.removed = removed;
    }
//</editor-fold>

}
